package top.ochiamalu.aioj.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.ochiamalu.aioj.common.ErrorCode;
import top.ochiamalu.aioj.constant.GenerateConstants;
import top.ochiamalu.aioj.constant.JudgeResultConstants;
import top.ochiamalu.aioj.converter.QuestionConverter;
import top.ochiamalu.aioj.converter.TestCaseConverters;
import top.ochiamalu.aioj.domain.bo.ChoiceOptionBO;
import top.ochiamalu.aioj.domain.bo.FullGenerateBO;
import top.ochiamalu.aioj.domain.bo.GenerateContentBO;
import top.ochiamalu.aioj.domain.bo.GenerateTagsBO;
import top.ochiamalu.aioj.domain.bo.GenerateTestCaseBO;
import top.ochiamalu.aioj.domain.bo.TestCaseBO;
import top.ochiamalu.aioj.domain.dto.question.AddQuestionDTO;
import top.ochiamalu.aioj.domain.dto.question.GenerateDTO;
import top.ochiamalu.aioj.domain.dto.question.PageQuestionDTO;
import top.ochiamalu.aioj.domain.dto.question.TestCaseDTO;
import top.ochiamalu.aioj.domain.dto.question.UpdateQuestionDTO;
import top.ochiamalu.aioj.domain.entity.Answer;
import top.ochiamalu.aioj.domain.entity.ChoiceQuestion;
import top.ochiamalu.aioj.domain.entity.ComprehensiveQuestion;
import top.ochiamalu.aioj.domain.entity.Favor;
import top.ochiamalu.aioj.domain.entity.FillBlanksQuestion;
import top.ochiamalu.aioj.domain.entity.JudgmentQuestion;
import top.ochiamalu.aioj.domain.entity.ProgrammingQuestion;
import top.ochiamalu.aioj.domain.entity.Question;
import top.ochiamalu.aioj.domain.entity.Set;
import top.ochiamalu.aioj.domain.entity.SetGroup;
import top.ochiamalu.aioj.domain.entity.TestCase;
import top.ochiamalu.aioj.domain.entity.Thumb;
import top.ochiamalu.aioj.domain.entity.User;
import top.ochiamalu.aioj.domain.vo.judge.TestCaseVO;
import top.ochiamalu.aioj.domain.vo.question.ChoiceOptionVO;
import top.ochiamalu.aioj.domain.vo.question.GenerateVO;
import top.ochiamalu.aioj.domain.vo.question.HotQuestionVO;
import top.ochiamalu.aioj.domain.vo.question.QuestionListVO;
import top.ochiamalu.aioj.domain.vo.question.QuestionVO;
import top.ochiamalu.aioj.domain.vo.question.RecentAcceptVO;
import top.ochiamalu.aioj.domain.vo.question.RecentUpdateQuestionVO;
import top.ochiamalu.aioj.domain.vo.question.SolveHistoryVO;
import top.ochiamalu.aioj.domain.vo.question.UpdateQuestionVO;
import top.ochiamalu.aioj.enums.DifficultyEnum;
import top.ochiamalu.aioj.enums.QuestionGenerateEnum;
import top.ochiamalu.aioj.enums.QuestionTypeEnum;
import top.ochiamalu.aioj.enums.ThumbTypeEnum;
import top.ochiamalu.aioj.exception.BusinessException;
import top.ochiamalu.aioj.mapper.QuestionMapper;
import top.ochiamalu.aioj.service.AnswerService;
import top.ochiamalu.aioj.service.ChoiceQuestionService;
import top.ochiamalu.aioj.service.ComprehensiveQuestionService;
import top.ochiamalu.aioj.service.FavorService;
import top.ochiamalu.aioj.service.FillBlanksQuestionService;
import top.ochiamalu.aioj.service.JudgmentQuestionService;
import top.ochiamalu.aioj.service.ProgrammingQuestionService;
import top.ochiamalu.aioj.service.QuestionService;
import top.ochiamalu.aioj.service.SetGroupService;
import top.ochiamalu.aioj.service.SetService;
import top.ochiamalu.aioj.service.TestCaseService;
import top.ochiamalu.aioj.service.ThumbService;
import top.ochiamalu.aioj.service.UserService;
import top.ochiamalu.aioj.util.AIUtils;
import top.ochiamalu.aioj.util.model.AIResult;

import javax.annotation.Resource;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 问题服务impl
 *
 * @author OchiaMalu
 * @date 2025/01/24
 */
@Service
@Slf4j
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question>
        implements QuestionService {

    private static final Gson GSON = new Gson();

    private static final Type LONG_LIST_TYPE = new TypeToken<List<Long>>() {
    }.getType();

    private static final Type STRING_LIST_TYPE = new TypeToken<List<String>>() {
    }.getType();

    @Resource
    private TestCaseService testCaseService;

    @Resource
    @Lazy
    private SetService setService;

    @Resource
    private SetGroupService setGroupService;

    @Resource
    private AnswerService answerService;

    @Resource
    private UserService userService;

    @Resource
    @Lazy
    private ThumbService thumbService;

    @Resource
    private FavorService favorService;

    @Resource
    private ProgrammingQuestionService programmingQuestionService;

    @Resource
    private ChoiceQuestionService choiceQuestionService;

    @Resource
    private JudgmentQuestionService judgmentQuestionService;

    @Resource
    private FillBlanksQuestionService fillBlanksQuestionService;

    @Resource
    private ComprehensiveQuestionService comprehensiveQuestionService;

    /**
     * 获取额外信息
     *
     * @param questionList 题目列表
     * @return {@link List }<{@link QuestionListVO }>
     */
    @NotNull
    private static List<QuestionListVO> getExtraInfo(List<Question> questionList) {
        return questionList.stream().map((question -> {
            QuestionListVO questionListVO = new QuestionListVO();
            questionListVO.setId(question.getId());
            questionListVO.setTitle(question.getTitle());
            if (question.getSubmitNum() == 0) {
                questionListVO.setRate("0%");
            } else {
                String rate = String.valueOf(question.getAcceptedNum() / question.getSubmitNum());
                questionListVO.setRate(rate + "%");
            }
            questionListVO.setDifficulty(question.getDifficulty());
            return questionListVO;
        })).collect(Collectors.toList());
    }

    @Override
    public List<QuestionListVO> listQuestions() {
        List<Question> questionList = this.list();
        return getExtraInfo(questionList);
    }

    /**
     * 添加题目
     *
     * @param addQuestionDTO 添加题目到
     * @return {@link Long }
     */
    @Override
    @Transactional
    public Long addQuestion(AddQuestionDTO addQuestionDTO) {
        Question question = QuestionConverter.INSTANCE
                .convertDTO2Entity(addQuestionDTO);
        if (addQuestionDTO.getTagList() != null) {
            question.setTags(GSON.toJson(addQuestionDTO.getTagList()));
        }
        boolean saved = this.save(question);
        if (!saved) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "添加失败");
        }
        if (addQuestionDTO.getType().equals(QuestionTypeEnum.PROGRAMMING.getCode())) {
            ProgrammingQuestion programmingQuestion = new ProgrammingQuestion();
            programmingQuestion.setQuestionId(question.getId());
            programmingQuestion.setLanguage(GSON.toJson(addQuestionDTO.getLanguage()));
            programmingQuestion.setTimeLimit(addQuestionDTO.getTimeLimit());
            programmingQuestionService.save(programmingQuestion);
            saveTestCaseInfo(question.getId(), addQuestionDTO.getTestCaseList());
        }
        if (addQuestionDTO.getType().equals(QuestionTypeEnum.MULTIPLE_CHOICE.getCode())) {
            addQuestionDTO.getChoiceOptionList().forEach(option -> {
                ChoiceQuestion choiceQuestion = new ChoiceQuestion();
                choiceQuestion.setQuestionId(question.getId());
                choiceQuestion.setScore(addQuestionDTO.getScore());
                choiceQuestion.setOption(option.getOption());
                choiceQuestion.setIsCorrect(option.getIsCorrect());
                choiceQuestion.setAnalysis(option.getAnalysis());
                choiceQuestionService.save(choiceQuestion);
            });
        }
        if (addQuestionDTO.getType().equals(QuestionTypeEnum.JUDGEMENT.getCode())) {
            JudgmentQuestion judgmentQuestion = new JudgmentQuestion();
            judgmentQuestion.setQuestionId(question.getId());
            judgmentQuestion.setScore(addQuestionDTO.getScore());
            judgmentQuestion.setIsCorrect(addQuestionDTO.getIsCorrect());
            judgmentQuestion.setAnalysis(addQuestionDTO.getAnalysis());
            judgmentQuestionService.save(judgmentQuestion);
        }
        if (addQuestionDTO.getType().equals(QuestionTypeEnum.FILL_BLANK.getCode())) {
            FillBlanksQuestion fillBlanksQuestion = new FillBlanksQuestion();
            fillBlanksQuestion.setQuestionId(question.getId());
            fillBlanksQuestion.setScore(addQuestionDTO.getScore());
            fillBlanksQuestion.setAnswer(GSON.toJson(addQuestionDTO.getAnswer()));
            fillBlanksQuestion.setAnalysis(addQuestionDTO.getAnalysis());
            fillBlanksQuestionService.save(fillBlanksQuestion);
        }
        if (addQuestionDTO.getType().equals(QuestionTypeEnum.COMPREHENSIVE.getCode())) {
            ComprehensiveQuestion comprehensiveQuestion = new ComprehensiveQuestion();
            comprehensiveQuestion.setQuestionId(question.getId());
            comprehensiveQuestion.setScore(addQuestionDTO.getScore());
            comprehensiveQuestion.setReferenceAnswer(addQuestionDTO.getReferenceAnswer());
            comprehensiveQuestion.setLengthLimit(addQuestionDTO.getLengthLimit());
            comprehensiveQuestionService.save(comprehensiveQuestion);
        }
        return question.getId();
    }

    /**
     * 通过id得到题目VO
     *
     * @param id 身份证件
     * @return {@link QuestionVO }
     */
    @Override
    public QuestionVO getQuestionById(Long id) {
        Question question = this.getById(id);
        if (question == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");
        }
        QuestionVO questionVO = QuestionConverter.INSTANCE
                .convertEntity2VO(question);

        questionVO.setTagList(GSON.fromJson(question.getTags(), STRING_LIST_TYPE));
        if (question.getType().equals(QuestionTypeEnum.PROGRAMMING.getCode())) {
            ProgrammingQuestion programmingQuestion = programmingQuestionService.lambdaQuery()
                    .eq(ProgrammingQuestion::getQuestionId, id)
                    .one();
            if (programmingQuestion != null) {
                questionVO.setLanguage(GSON.fromJson(programmingQuestion.getLanguage(), STRING_LIST_TYPE));
                questionVO.setTimeLimit(programmingQuestion.getTimeLimit());
                questionVO.setMemoryLimit(programmingQuestion.getMemoryLimit());
            }
        }
        if (question.getType().equals(QuestionTypeEnum.MULTIPLE_CHOICE.getCode())) {
            List<ChoiceQuestion> choiceQuestionList = choiceQuestionService.lambdaQuery()
                    .eq(ChoiceQuestion::getQuestionId, id)
                    .list();
            AtomicInteger correct = new AtomicInteger();
            if (choiceQuestionList != null) {
                List<ChoiceOptionVO> choiceOptionVOList = choiceQuestionList.stream().map(choiceQuestion -> {
                    ChoiceOptionVO choiceOptionVO = new ChoiceOptionVO();
                    choiceOptionVO.setId(choiceQuestion.getId());
                    choiceOptionVO.setOption(choiceQuestion.getOption());
                    if (choiceQuestion.getIsCorrect() == 1) {
                        correct.getAndIncrement();
                    }
                    return choiceOptionVO;
                }).collect(Collectors.toList());
                questionVO.setChoiceOptionList(choiceOptionVOList);
            }
            questionVO.setIsMultiple(correct.get() > 1 ? 1 : 0);
        }
        if (question.getType().equals(QuestionTypeEnum.FILL_BLANK.getCode())) {
            FillBlanksQuestion fillBlanksQuestion = fillBlanksQuestionService.lambdaQuery()
                    .eq(FillBlanksQuestion::getQuestionId, id)
                    .one();
            if (fillBlanksQuestion != null) {
                List<String> answer = GSON.fromJson(fillBlanksQuestion.getAnswer(), STRING_LIST_TYPE);
                questionVO.setFillBlankNum(answer.size());
            }
        }

        boolean login = StpUtil.isLogin();
        if (login) {
            long userId = StpUtil.getLoginIdAsLong();
            Long thumbCount = thumbService.lambdaQuery().eq(Thumb::getUserId, userId)
                    .eq(Thumb::getTargetId, question.getId())
                    .eq(Thumb::getType, ThumbTypeEnum.QUESTION.getValue())
                    .count();
            questionVO.setIsThumb(thumbCount > 0);

            Long favorCount = favorService.lambdaQuery().eq(Favor::getUserId, userId)
                    .eq(Favor::getTargetId, question.getId())
                    .eq(Favor::getType, ThumbTypeEnum.QUESTION.getValue())
                    .count();
            questionVO.setIsFavour(favorCount > 0);
        }
        return questionVO;
    }

    /**
     * 分页题目
     *
     * @param pageQuestionDTO 页面题目到
     * @return {@link Page }<{@link QuestionListVO }>
     */
    @Override
    public Page<QuestionListVO> pageQuestions(PageQuestionDTO pageQuestionDTO) {
        LambdaQueryWrapper<Question> wrapper = new LambdaQueryWrapper<>();
        if (pageQuestionDTO.getQuestionSet() != null) {
            java.util.Set<Long> questionIds = getQuestionIdsInSet(pageQuestionDTO.getQuestionSet());
            wrapper.in(Question::getId, questionIds);
        }
        wrapper.like(
                        StringUtils.isNotBlank(pageQuestionDTO.getSearchText()),
                        Question::getTitle, pageQuestionDTO.getSearchText()
                )
                .eq(
                        pageQuestionDTO.getDifficulty() != null,
                        Question::getDifficulty, pageQuestionDTO.getDifficulty()
                );
        if (pageQuestionDTO.getTagList() != null && !pageQuestionDTO.getTagList().isEmpty()) {
            pageQuestionDTO.getTagList().forEach(tag -> {
                wrapper.like(Question::getTags, tag);
            });
        }
        Page<Question> questionPage = this.page(
                new Page<>(pageQuestionDTO.getCurrentPage(), pageQuestionDTO.getPageSize()),
                wrapper
        );
        Page<QuestionListVO> questionVOPage = new Page<>();
        BeanUtils.copyProperties(questionPage, questionVOPage, "records");
        List<QuestionListVO> questionVOList = getExtraInfo(questionPage.getRecords());
        questionVOPage.setRecords(questionVOList);
        return questionVOPage;
    }

    private java.util.Set<Long> getQuestionIdsInSet(Long setId) {
        Set set = setService.getById(setId);
        String groupIds = set.getGroupId();
        List<Long> setGroupIdList = GSON.fromJson(groupIds, LONG_LIST_TYPE);

        java.util.Set<Long> finalQuestionIdSet = new HashSet<>();
        setGroupIdList.forEach(setGroupId -> {
            SetGroup setGroup = setGroupService.getById(setGroupId);
            String questionIds = setGroup.getQuestionId();
            List<Long> questionIdList = GSON.fromJson(questionIds, LONG_LIST_TYPE);
            finalQuestionIdSet.addAll(questionIdList);
        });
        return finalQuestionIdSet;
    }

    /**
     * 通过id得到详细题目信息
     *
     * @param id 身份证件
     * @return {@link UpdateQuestionVO }
     */
    @Override
    public UpdateQuestionVO getQuestionDetailById(Long id) {
        Question question = this.getById(id);
        if (question == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");
        }
        UpdateQuestionVO updateQuestionVO = QuestionConverter.INSTANCE
                .convertEntity2UpdateVO(question);

        Type stringType = new TypeToken<List<String>>() {
        }.getType();
        updateQuestionVO.setTagList(GSON.fromJson(question.getTags(), stringType));
        if (question.getType().equals(QuestionTypeEnum.PROGRAMMING.getCode())) {
            ProgrammingQuestion programmingQuestion = programmingQuestionService.lambdaQuery()
                    .eq(ProgrammingQuestion::getQuestionId, id)
                    .one();
            if (programmingQuestion != null && programmingQuestion.getLanguage() != null) {
                updateQuestionVO.setLanguage(GSON.fromJson(programmingQuestion.getLanguage(), stringType));
            }
            List<TestCase> testCaseInfoList = testCaseService.lambdaQuery()
                    .eq(TestCase::getQuestionId, id)
                    .list();
            updateQuestionVO.setTestCaseList(testCaseInfoList);
        }
        if (question.getType().equals(QuestionTypeEnum.MULTIPLE_CHOICE.getCode())) {
            List<ChoiceQuestion> choiceQuestionList = choiceQuestionService.lambdaQuery()
                    .eq(ChoiceQuestion::getQuestionId, id)
                    .list();
            List<ChoiceOptionVO> choiceOptionDTOList = choiceQuestionList.stream().map(choiceQuestion -> {
                ChoiceOptionVO choiceOptionVO = new ChoiceOptionVO();
                choiceOptionVO.setOption(choiceQuestion.getOption());
                choiceOptionVO.setIsCorrect(choiceQuestion.getIsCorrect());
                choiceOptionVO.setAnalysis(choiceQuestion.getAnalysis());
                return choiceOptionVO;
            }).collect(Collectors.toList());
            updateQuestionVO.setChoiceOptionList(choiceOptionDTOList);
            updateQuestionVO.setScore(choiceQuestionList.get(0).getScore());
        }
        if (question.getType().equals(QuestionTypeEnum.JUDGEMENT.getCode())) {
            JudgmentQuestion judgmentQuestion = judgmentQuestionService.lambdaQuery()
                    .eq(JudgmentQuestion::getQuestionId, id)
                    .one();
            updateQuestionVO.setIsCorrect(judgmentQuestion.getIsCorrect());
            updateQuestionVO.setAnalysis(judgmentQuestion.getAnalysis());
            updateQuestionVO.setScore(judgmentQuestion.getScore());
        }
        if (question.getType().equals(QuestionTypeEnum.FILL_BLANK.getCode())) {
            FillBlanksQuestion fillBlanksQuestion = fillBlanksQuestionService.lambdaQuery().eq(FillBlanksQuestion::getQuestionId, id)
                    .one();
            updateQuestionVO.setAnswer(GSON.fromJson(fillBlanksQuestion.getAnswer(), STRING_LIST_TYPE));
            updateQuestionVO.setAnalysis(fillBlanksQuestion.getAnalysis());
            updateQuestionVO.setScore(fillBlanksQuestion.getScore());
        }
        if (question.getType().equals(QuestionTypeEnum.COMPREHENSIVE.getCode())) {
            ComprehensiveQuestion comprehensiveQuestion = comprehensiveQuestionService.lambdaQuery()
                    .eq(ComprehensiveQuestion::getQuestionId, id)
                    .one();
            updateQuestionVO.setReferenceAnswer(comprehensiveQuestion.getReferenceAnswer());
            updateQuestionVO.setLengthLimit(comprehensiveQuestion.getLengthLimit());
            updateQuestionVO.setScore(comprehensiveQuestion.getScore());
        }
        return updateQuestionVO;
    }

    /**
     * 更新题目
     *
     * @param updateQuestionDTO 更新题目到
     * @return boolean
     */
    @Override
    @Transactional
    public boolean updateQuestion(UpdateQuestionDTO updateQuestionDTO) {
        Question question = QuestionConverter.INSTANCE
                .convertUpdateDTO2Entity(updateQuestionDTO);
        if (updateQuestionDTO.getTags() != null) {
            question.setTags(GSON.toJson(updateQuestionDTO.getTags()));
        }

        boolean updated = this.updateById(question);
        if (!updated) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新失败");
        }
        if (updateQuestionDTO.getType().equals(QuestionTypeEnum.PROGRAMMING.getCode())) {
            ProgrammingQuestion programmingQuestion = programmingQuestionService.lambdaQuery()
                    .eq(ProgrammingQuestion::getQuestionId, updateQuestionDTO.getId())
                    .one();
            if (programmingQuestion != null) {
                programmingQuestion.setLanguage(GSON.toJson(updateQuestionDTO.getLanguage()));
                programmingQuestion.setTimeLimit(updateQuestionDTO.getTimeLimit());
                programmingQuestion.setMemoryLimit(updateQuestionDTO.getMemoryLimit());
                programmingQuestionService.updateById(programmingQuestion);
            } else {
                programmingQuestion = new ProgrammingQuestion();
                programmingQuestion.setQuestionId(updateQuestionDTO.getId());
                programmingQuestion.setLanguage(GSON.toJson(updateQuestionDTO.getLanguage()));
                programmingQuestion.setTimeLimit(updateQuestionDTO.getTimeLimit());
                programmingQuestion.setMemoryLimit(updateQuestionDTO.getMemoryLimit());
                programmingQuestionService.save(programmingQuestion);
            }
            testCaseService.lambdaUpdate().eq(TestCase::getQuestionId, updateQuestionDTO.getId()).remove();
            saveTestCaseInfo(updateQuestionDTO.getId(), updateQuestionDTO.getTestCaseList());
        }
        if (updateQuestionDTO.getType().equals(QuestionTypeEnum.MULTIPLE_CHOICE.getCode())) {
            boolean removed = choiceQuestionService.lambdaUpdate()
                    .eq(ChoiceQuestion::getQuestionId, updateQuestionDTO.getId())
                    .remove();
            if (!removed) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除失败");
            }
            updateQuestionDTO.getChoiceOptionList().forEach(option -> {
                ChoiceQuestion choiceQuestion = new ChoiceQuestion();
                choiceQuestion.setQuestionId(question.getId());
                choiceQuestion.setScore(updateQuestionDTO.getScore());
                choiceQuestion.setOption(option.getOption());
                choiceQuestion.setIsCorrect(option.getIsCorrect());
                choiceQuestion.setAnalysis(option.getAnalysis());
                choiceQuestionService.save(choiceQuestion);
            });
        }
        if (updateQuestionDTO.getType().equals(QuestionTypeEnum.JUDGEMENT.getCode())) {
            JudgmentQuestion judgmentQuestion = judgmentQuestionService.lambdaQuery()
                    .eq(JudgmentQuestion::getQuestionId, updateQuestionDTO.getId())
                    .one();
            judgmentQuestion.setScore(updateQuestionDTO.getScore());
            judgmentQuestion.setIsCorrect(updateQuestionDTO.getIsCorrect());
            judgmentQuestion.setAnalysis(updateQuestionDTO.getAnalysis());
            judgmentQuestionService.updateById(judgmentQuestion);
        }
        if (updateQuestionDTO.getType().equals(QuestionTypeEnum.FILL_BLANK.getCode())) {
            FillBlanksQuestion fillBlanksQuestion = fillBlanksQuestionService.lambdaQuery()
                    .eq(FillBlanksQuestion::getQuestionId, updateQuestionDTO.getId())
                    .one();
            fillBlanksQuestion.setScore(updateQuestionDTO.getScore());
            fillBlanksQuestion.setAnswer(GSON.toJson(updateQuestionDTO.getAnswer()));
            fillBlanksQuestion.setAnalysis(updateQuestionDTO.getAnalysis());
            fillBlanksQuestionService.updateById(fillBlanksQuestion);
        }
        if (updateQuestionDTO.getType().equals(QuestionTypeEnum.COMPREHENSIVE.getCode())) {
            ComprehensiveQuestion comprehensiveQuestion = comprehensiveQuestionService.lambdaQuery()
                    .eq(ComprehensiveQuestion::getQuestionId, updateQuestionDTO.getId())
                    .one();
            comprehensiveQuestion.setReferenceAnswer(updateQuestionDTO.getReferenceAnswer());
            comprehensiveQuestion.setLengthLimit(updateQuestionDTO.getLengthLimit());
            comprehensiveQuestion.setScore(updateQuestionDTO.getScore());
            comprehensiveQuestionService.updateById(comprehensiveQuestion);
        }
        return true;
    }

    @Override
    public Integer getTotalScore(Long id) {
        return testCaseService.lambdaQuery()
                .eq(TestCase::getQuestionId, id)
                .list()
                .stream()
                .mapToInt(TestCase::getScore)
                .sum();
    }

    @Override
    public List<HotQuestionVO> listHotQuestions() {
        List<Question> questionList = this.lambdaQuery().last("limit 20").list();
        return QuestionConverter.INSTANCE.convertList2HotQuestionVOList(questionList);
    }

    @Override
    public List<RecentUpdateQuestionVO> listRecentUpdateQuestions() {
        List<Question> questionList = this.lambdaQuery().last("limit 20").list();
        return QuestionConverter.INSTANCE.convertList2RecentUpdateQuestionVOList(questionList);
    }

    @Override
    @Transactional
    public boolean deleteQuestion(Long id) {
        Question question = this.getById(id);
        if (question == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目不存在");
        }
        boolean removed = this.removeById(id);
        if (!removed) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除失败");
        }
        if (question.getType().equals(QuestionTypeEnum.PROGRAMMING.getCode())) {
            testCaseService.lambdaUpdate().eq(TestCase::getQuestionId, id).remove();
        }
        if (question.getType().equals(QuestionTypeEnum.MULTIPLE_CHOICE.getCode())) {
            choiceQuestionService.lambdaUpdate()
                    .eq(ChoiceQuestion::getQuestionId, id)
                    .remove();
        }
        if (question.getType().equals(QuestionTypeEnum.JUDGEMENT.getCode())) {
            judgmentQuestionService.lambdaUpdate()
                    .eq(JudgmentQuestion::getQuestionId, id)
                    .remove();
        }
        if (question.getType().equals(QuestionTypeEnum.FILL_BLANK.getCode())) {
            fillBlanksQuestionService.lambdaUpdate()
                    .eq(FillBlanksQuestion::getQuestionId, id)
                    .remove();
        }
        if (question.getType().equals(QuestionTypeEnum.COMPREHENSIVE.getCode())) {
            comprehensiveQuestionService.lambdaUpdate()
                    .eq(ComprehensiveQuestion::getQuestionId, id)
                    .remove();
        }
        return true;
    }

    @Override
    public List<RecentAcceptVO> listRecentAcceptQuestions(String account) {
        User user = userService.lambdaQuery().eq(User::getAccount, account).one();
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在");
        }
        List<Answer> answerList = answerService.lambdaQuery()
                .eq(Answer::getUserId, user.getId())
                .eq(Answer::getStatus, JudgeResultConstants.ACCEPTED)
                .orderByDesc(Answer::getSubmitTime)
                .list();
        return answerList.stream().map(this::convertToRecentAcceptVO).collect(Collectors.toList());
    }

    @Override
    public SolveHistoryVO getSolveHistory(String account) {
        SolveHistoryVO solveHistoryVO = new SolveHistoryVO();
        solveHistoryVO.setHardCount(this.countHard());
        solveHistoryVO.setMediumCount(this.countMedium());
        solveHistoryVO.setEasyCount(this.countEasy());

        Long userId = userService.getUserIdByAccount(account);
        List<Answer> answerList = answerService.lambdaQuery()
                .eq(Answer::getUserId, userId)
                .eq(Answer::getStatus, JudgeResultConstants.ACCEPTED)
                .list();

        // 初始化解决题目计数
        solveHistoryVO.setSolvedEasy(0L);
        solveHistoryVO.setSolvedMedium(0L);
        solveHistoryVO.setSolvedHard(0L);

        // 收集所有已解决的题目ID
        List<Long> questionIds = answerList.stream()
                .map(Answer::getQuestionId)
                .distinct()
                .collect(Collectors.toList());

        if (!questionIds.isEmpty()) {
            List<Question> questions = this.lambdaQuery()
                    .in(Question::getId, questionIds)
                    .list();

            // 按难度统计题目数量
            for (Question question : questions) {
                switch (question.getDifficulty()) {
                    case 0:
                        solveHistoryVO.setSolvedEasy(solveHistoryVO.getSolvedEasy() + 1);
                        break;
                    case 1:
                        solveHistoryVO.setSolvedMedium(solveHistoryVO.getSolvedMedium() + 1);
                        break;
                    case 2:
                        solveHistoryVO.setSolvedHard(solveHistoryVO.getSolvedHard() + 1);
                        break;
                }
            }
        }

        return solveHistoryVO;
    }

    @Override
    public Long countHard() {
        return this.lambdaQuery().eq(Question::getDifficulty, DifficultyEnum.HARD.getCode()).count();
    }

    @Override
    public Long countMedium() {
        return this.lambdaQuery().eq(Question::getDifficulty, DifficultyEnum.MEDIUM.getCode()).count();
    }

    @Override
    public Long countEasy() {
        return this.lambdaQuery().eq(Question::getDifficulty, DifficultyEnum.EASY.getCode()).count();
    }

    @Override
    public GenerateVO generate(GenerateDTO generateDTO) {
        QuestionGenerateEnum generateEnum = QuestionGenerateEnum.getEnumByType(generateDTO.getType());
        if (generateEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "无效的操作类型");
        }

        GenerateVO generateVO = new GenerateVO();
        switch (generateEnum) {
            case CONTENT:
                generateVO.setContent(generateContent(generateDTO.getTitle()));
                break;
            case TAGS:
                generateVO.setTagList(generateTags(generateDTO.getTitle(), generateDTO.getContent()));
                break;
            case TEST_CASE:
                generateVO.setTestCaseList(generateTestCase(generateDTO.getTitle(), generateDTO.getContent()));
                break;
            case FULL:
                return fullGenerate(generateDTO.getQuestionType(), generateDTO.getDifficulty(), generateDTO.getTagList(), generateDTO.getAdditional());
        }
        return generateVO;
    }

    private String generateContent(String title) {
        GenerateContentBO generateContentBO = new GenerateContentBO();
        generateContentBO.setTitle(title);

        String message = String.format(
                GenerateConstants.GENERATE_CONTENT_PROMPT,
                GSON.toJson(generateContentBO)
        );

        AIResult result = AIUtils.getInstance().sendMessage(message, false, false);
        String content = handleResult(result.getContent());

        try {
            JsonObject jsonObject = GSON.fromJson(content, JsonObject.class);
            if (jsonObject.has("content")) {
                return jsonObject.get("content").getAsString();
            }

            return handleInvalidResponse("content", content);
        } catch (Exception e) {
            return handleJsonParseException(e);
        }
    }

    private List<String> generateTags(String title, String content) {
        GenerateTagsBO generateTagsBO = new GenerateTagsBO();
        generateTagsBO.setTitle(title);
        generateTagsBO.setContent(content);

        String message = String.format(
                GenerateConstants.GENERATE_TAGS_PROMPT,
                GSON.toJson(generateTagsBO)
        );

        AIResult result = AIUtils.getInstance().sendMessage(message, false, false);
        String handledResult = handleResult(result.getContent());

        try {
            JsonObject jsonObject = GSON.fromJson(handledResult, JsonObject.class);
            if (jsonObject.has("tags")) {
                JsonArray jsonArray = jsonObject.get("tags").getAsJsonArray();
                List<String> tags = new ArrayList<>(jsonArray.size());
                jsonArray.forEach(element -> tags.add(element.getAsString()));
                return tags;
            }

            return handleInvalidResponse("tags", handledResult);
        } catch (Exception e) {
            return handleJsonParseException(e);
        }
    }

    private List<TestCaseVO> generateTestCase(String title, String content) {
        GenerateTestCaseBO generateTestCaseBO = new GenerateTestCaseBO();
        generateTestCaseBO.setTitle(title);
        generateTestCaseBO.setContent(content);

        String message = String.format(
                GenerateConstants.GENERATE_TESTCASE_PROMPT,
                GSON.toJson(generateTestCaseBO)
        );

        AIResult result = AIUtils.getInstance().sendMessage(message, false, false);
        String handledResult = handleResult(result.getContent());

        try {
            JsonObject jsonObject = GSON.fromJson(handledResult, JsonObject.class);
            if (jsonObject.has("testCase")) {
                JsonArray jsonArray = jsonObject.get("testCase").getAsJsonArray();
                List<TestCaseBO> testCaseBOS = new ArrayList<>(jsonArray.size());
                jsonArray.forEach(element -> testCaseBOS.add(GSON.fromJson(element, TestCaseBO.class)));
                return TestCaseConverters.INSTANCE
                        .convertBOList2VO(testCaseBOS);
            }

            return handleInvalidResponse("testCase", handledResult);
        } catch (Exception e) {
            return handleJsonParseException(e);
        }
    }

    private GenerateVO fullGenerate(Integer questionType, Integer difficulty, List<String> tags, String additional) {
        FullGenerateBO fullGenerateBO = new FullGenerateBO();
        fullGenerateBO.setDifficulty(difficulty);
        fullGenerateBO.setTags(tags);
        fullGenerateBO.setAdditional(additional);
        String jsonStr = GSON.toJson(fullGenerateBO);
        String prompt;
        QuestionTypeEnum questionTypeEnum = QuestionTypeEnum.getEnumByCode(questionType);
        if (questionTypeEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持的题目类型");
        }
        switch (questionTypeEnum) {
            case PROGRAMMING:
                prompt = GenerateConstants.FULL_GENERATE_PROMPT;
                break;
            case MULTIPLE_CHOICE:
                prompt = GenerateConstants.CHOICE_QUESTION_GENERATE_PROMPT;
                break;
            case FILL_BLANK:
                prompt = GenerateConstants.FILL_BLANK_QUESTION_GENERATE_PROMPT;
                break;
            case JUDGEMENT:
                prompt = GenerateConstants.JUDGEMENT_QUESTION_GENERATE_PROMPT;
                break;
            case COMPREHENSIVE:
                prompt = GenerateConstants.COMPREHENSIVE_QUESTION_GENERATE_PROMPT;
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持的题目类型");
        }
        String message = String.format(
                prompt,
                jsonStr
        );
        AIResult result = AIUtils.getInstance().sendMessage(message, false, false);
        String handledResult = handleResult(result.getContent());
        try {
            JsonObject jsonObject = GSON.fromJson(handledResult, JsonObject.class);
            GenerateVO generateVO = new GenerateVO();
            if (
                    jsonObject.has("title") &&
                            jsonObject.has("content") &&
                            jsonObject.has("tags")
            ) {
                generateVO.setTitle(jsonObject.get("title").getAsString());
                generateVO.setContent(jsonObject.get("content").getAsString());
                generateVO.setTagList(GSON.fromJson(jsonObject.get("tags"), new TypeToken<List<String>>() {
                }.getType()));
            }
            if (questionTypeEnum == QuestionTypeEnum.PROGRAMMING) {
                if (jsonObject.has("testCase")) {
                    JsonArray jsonArray = jsonObject.get("testCase").getAsJsonArray();
                    List<TestCaseBO> testCaseBOS = new ArrayList<>(jsonArray.size());
                    jsonArray.forEach(element -> testCaseBOS.add(GSON.fromJson(element, TestCaseBO.class)));
                    generateVO.setTestCaseList(TestCaseConverters.INSTANCE
                            .convertBOList2VO(testCaseBOS));
                    return generateVO;
                }
            }
            if (questionTypeEnum == QuestionTypeEnum.MULTIPLE_CHOICE) {
                if (jsonObject.has("options")) {
                    JsonArray jsonArray = jsonObject.get("options").getAsJsonArray();
                    List<ChoiceOptionBO> choiceOptionBOS = new ArrayList<>(jsonArray.size());
                    jsonArray.forEach(element -> choiceOptionBOS.add(GSON.fromJson(element, ChoiceOptionBO.class)));
                    generateVO.setChoiceOptionList(choiceOptionBOS);
                    return generateVO;
                }
            }
            if (questionTypeEnum == QuestionTypeEnum.FILL_BLANK) {
                if (jsonObject.has("answer")) {
                    JsonArray jsonArray = jsonObject.get("answer").getAsJsonArray();
                    List<String> answer = new ArrayList<>(jsonArray.size());
                    jsonArray.forEach(element -> answer.add(element.getAsString()));
                    generateVO.setAnswer(answer);
                    return generateVO;
                }
            }
            if (questionTypeEnum == QuestionTypeEnum.JUDGEMENT) {
                if (jsonObject.has("isCorrect")) {
                    generateVO.setIsCorrect(jsonObject.get("isCorrect").getAsInt());
                }
                if (jsonObject.has("analysis")) {
                    generateVO.setAnalysis(jsonObject.get("analysis").getAsString());
                }
                return generateVO;
            }
            if (questionTypeEnum == QuestionTypeEnum.COMPREHENSIVE) {
                if (jsonObject.has("referenceAnswer")) {
                    generateVO.setReferenceAnswer(jsonObject.get("referenceAnswer").getAsString());
                }
                if (jsonObject.has("analysis")) {
                    generateVO.setAnalysis(jsonObject.get("analysis").getAsString());
                }
                return generateVO;
            }
            return handleInvalidResponse("full-gen", handledResult);
        } catch (Exception e) {
            return handleJsonParseException(e);
        }
    }

    private String handleResult(String content) {
        // 移除可能存在的JSON代码块标记
        return content.replaceAll("^```json\\s*|\\s*```$", "").trim();
    }

    /**
     * 处理无效的AI响应
     *
     * @param expectedField 期望的字段
     * @param response      AI返回内容
     * @param <T>           返回类型
     * @return 不会返回，总是抛出异常
     */
    private <T> T handleInvalidResponse(String expectedField, String response) {
        log.error("AI返回内容格式不正确，缺少「{}」字段: {}", expectedField, response);
        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "AI返回内容格式不正确，请重新生成");
    }

    /**
     * 处理JSON解析异常
     *
     * @param e   异常
     * @param <T> 返回类型
     * @return 不会返回，总是抛出异常
     */
    private <T> T handleJsonParseException(Exception e) {
        log.error("解析AI返回内容时出错: {}", e.getMessage());
        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "解析结果失败，请重新生成");
    }

    /**
     * 将Answer转换为RecentAcceptVO
     *
     * @param answer 答题记录
     * @return RecentAcceptVO
     */
    private RecentAcceptVO convertToRecentAcceptVO(Answer answer) {
        RecentAcceptVO recentAcceptVO = new RecentAcceptVO();
        recentAcceptVO.setId(answer.getQuestionId());
        Question question = this.getById(answer.getQuestionId());
        recentAcceptVO.setTitle(question.getTitle());
        recentAcceptVO.setTime(formatTimeAgo(answer.getSubmitTime()));
        return recentAcceptVO;
    }

    /**
     * 将时间转换为友好的中文格式
     *
     * @param date 时间
     * @return 友好的中文时间格式
     */
    private String formatTimeAgo(Date date) {
        long now = System.currentTimeMillis();
        long diff = now - date.getTime();

        long days = diff / (1000 * 60 * 60 * 24);
        if (days == 0) {
            long hours = diff / (1000 * 60 * 60);
            if (hours == 0) {
                long minutes = diff / (1000 * 60);
                return minutes == 0 ? "刚刚" : minutes + "分钟前";
            }
            return hours + "小时前";
        }
        if (days < 7) {
            return days + "天前";
        }
        if (days < 30) {
            return (days / 7) + "周前";
        }
        if (days < 365) {
            return (days / 30) + "个月前";
        }
        return (days / 365) + "年前";
    }

    /**
     * 保存测试用例
     *
     * @param questionId      题目身份证件
     * @param testCaseDTOList 测试用例列表
     */
    private void saveTestCaseInfo(Long questionId, List<TestCaseDTO> testCaseDTOList) {
        testCaseDTOList.forEach(testCase -> {
            TestCase testCaseInfo = new TestCase();
            testCaseInfo.setQuestionId(questionId);
            testCaseInfo.setInput(testCase.getInput());
            testCaseInfo.setOutput(testCase.getOutput());
            testCaseInfo.setHint(testCase.getHint());
            if (testCase.getScore() == null) {
                testCase.setScore(0);
            }
            testCaseInfo.setScore(testCase.getScore());
            testCaseService.save(testCaseInfo);
        });
    }
}




